/******************************************************************************
 * @file  gkt_core_irq.c
 * @date  18/Mar/2021
 ******************************************************************************/

#include "gkt_board.h"
#include "gkt_defines.h"
#include "gkt_types.h"
#include "gkt_debug.h"
#include "gkt_malloc.h"

#if defined(GKT_CONFIG_DEBUG_ENABLE) && GKT_CONFIG_DEBUG_ENABLE

/************************************************************
 * EXC_RETURN[31:0] Description
 * ----------------------------------------------------------
 * 0xFFFFFFF1  Return to Handler mode
 *             Exception return gets state from MSP.
 *             Execution uses MSP after return.
 *
 * 0xFFFFFFF9  Return to Thread mode
 *             Exception return gets state from MSP.
 *             Execution uses MSP after return.
 *
 * 0xFFFFFFFD  Return to Thread mode
 *             Exception return gets state from PSP.
 *             Execution uses PSP after return.
 ************************************************************/

struct _excep_transmit_stack_frame {
	uint32_t	irq_no;
	uint32_t	EXC_RETURN;
} __ALIGNED(8);
typedef struct _excep_transmit_stack_frame	excep_transmit_stack_frame_s;
#define EXCEP_TRANSMIT_STACK_FRAME_SIZE	sizeof(excep_transmit_stack_frame_s)

/* stack frame without floating-point state */
struct _excep_stack_frame {
	uint32_t	R0, R1, R2, R3;
	uint32_t	R12, LR, PC, xPSR;
} __ALIGNED(8);
typedef struct _excep_stack_frame	excep_stack_frame_s;
#define EXCEP_STACK_FRAME_SIZE	sizeof(excep_stack_frame_s)

typedef struct _excep_info {
	uint32_t	R4, R5, R6, R7;
	uint32_t	R8, R9, R10, R11;
	uint32_t	PSP, MSP, EXC_RETURN, PSR;
} excep_info_s;
static excep_info_s s_excep_info;

#define system_exception_init_info()	\
	do {	\
		__asm volatile ("mov %0, r4		\n"	: "=r" (s_excep_info.R4));	\
		__asm volatile ("mov %0, r5 	\n" : "=r" (s_excep_info.R5));	\
		__asm volatile ("mov %0, r6		\n"	: "=r" (s_excep_info.R6));	\
		__asm volatile ("mov %0, r7 	\n" : "=r" (s_excep_info.R7));	\
		__asm volatile ("mov %0, r8		\n"	: "=r" (s_excep_info.R8));	\
		__asm volatile ("mov %0, r9 	\n" : "=r" (s_excep_info.R9));	\
		__asm volatile ("mov %0, r10	\n"	: "=r" (s_excep_info.R10));	\
		__asm volatile ("mov %0, r11 	\n" : "=r" (s_excep_info.R11));	\
		__asm volatile ("mrs %0, psp	\n"	: "=r" (s_excep_info.PSP));	\
		__asm volatile ("mrs %0, msp	\n"	: "=r" (s_excep_info.MSP));	\
		__asm volatile ("mov %0, lr		\n"	: "=r" (s_excep_info.EXC_RETURN));	\
		__asm volatile ("mrs %0, PSR	\n"	: "=r" (s_excep_info.PSR));	\
	} while (0)

static void system_exception_trace_frame_one(uint32_t stack_base)
{
	uint32_t *stack_frame, *stack_frame_end;
	
	stack_frame = (uint32_t *)stack_base;
	stack_frame_end = stack_frame + 128;
	if ((uint32_t)stack_frame_end > (GKT_SRAM_BASEADDR + GKT_SRAM_SIZE))
		stack_frame_end = (uint32_t *)(GKT_SRAM_BASEADDR + GKT_SRAM_SIZE);

	while ((stack_frame + 4) <= stack_frame_end) {
		gkt_printf("0x%08X: %08X %08X %08X %08X\n",(uint32_t)stack_frame, 
			stack_frame[0], stack_frame[1], stack_frame[2], stack_frame[3]);
		stack_frame += 4;
	}
}

static void system_exception_trace_frame(void)
{
	gkt_printf("------------------------------------------------------------\n");
	gkt_printf("-- MSP:\n");
	gkt_printf("------------------------------------------------------------\n");
	system_exception_trace_frame_one(s_excep_info.MSP);

	gkt_printf("------------------------------------------------------------\n");
	gkt_printf("-- PSP:\n");
	system_exception_trace_frame_one(s_excep_info.PSP);
	gkt_printf("------------------------------------------------------------\n");
}

void __NAKED HardFault_Handler(void)
{
	system_exception_init_info();
	
	gkt_printf("************************************************************\n");
	gkt_printf("* HardFault.\n");
	gkt_printf("------------------------------------------------------------\n");
	gkt_printf("SCB: ICSR(%08x) SCR(%08x) CCR(%08x) \n", 
		SCB->ICSR, SCB->SCR, SCB->CCR);

	gkt_printf("------------------------------------------------------------\n");
	gkt_printf("CORE: R4(%08x) R5(%08x) R6(%08x) R7(%08x)\n",
		s_excep_info.R4, s_excep_info.R5, s_excep_info.R6, s_excep_info.R7);
	gkt_printf("CORE: R8(%08x) R9(%08x) R10(%08x) R11(%08x)\n",
		s_excep_info.R8, s_excep_info.R9, s_excep_info.R10, s_excep_info.R11);
	gkt_printf("CORE: PSP(%08x) MSP(%08x) LR(%08x) PSR(%08x)\n",
		s_excep_info.PSP, s_excep_info.MSP, s_excep_info.EXC_RETURN, s_excep_info.PSR);
	
	system_exception_trace_frame();
	gkt_printf("************************************************************\n");
	
	gkt_malloc_free_show_record("HardFault");
	
	__BKPT(0);
}

#endif
